import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

# 与一维（1D）信号处理一样，可以对2D 图像实施低通滤波（LPF）和高通滤波（HPF）处理。LPF 帮助我们去除噪音，模糊图像。HPF 帮助我们找到图像的边
# 缘。图像高通滤波处理中，主要有一阶导数（Sobel和Scharr）和二阶导数（Laplacian）。参照下图（一个原始图，3个目标图），利用OpenCV+Python环境，
# 按照下列步骤，完成原始图的3个滤波处理。（30分）
# （8）确定水平方向梯度（x_gradient）的滤波核
kernel_x = np.float32([
    [1, 0, -1],
    [1, 0, -1],
    [1, 0, -1],
])

# （9）确定垂直方向梯度（y_gradient）的滤波核
kernel_y = np.float32([
    [1, 1, 1],
    [0, 0, 0],
    [-1, -1, -1],
])

# （10）确定高斯（laplacian）滤波核
kernel_lap = np.float32([
    [0, 1, 0],
    [1, -4, 1],
    [0, 1, 0],
])


# （11）定义底层计算卷积函数convoluation(image, kernel)
def convoluation(img,kernel):
    img_shape = img.shape
    H, W = img_shape[0], img_shape[1]
    kh, kw = kernel.shape
    dst_h, dst_w = H + 1 - kh, W + 1 - kw
    dst = np.zeros((dst_h, dst_w), dtype=np.float32)
    for i in range(dst_h):
        for j in range(dst_w):
            roi = img[i:i+kh, j:j+kw]
            dst[i, j] = (roi * kernel).sum()
    return dst


# （12）分别调用函数convoluation()计算原始图像对3个滤波核的卷积
img = cv.imread('images/sudoku.png', cv.IMREAD_GRAYSCALE)
print('Calculating convolutions ...')
img_sobel_x = convoluation(img, kernel_x)
img_sobel_y = convoluation(img, kernel_y)
img_lap = convoluation(img, kernel_lap)
print('Done')

# （13）用2行2列显示原始图像和3个目标图像
spr = 2
spc = 2
spn = 0
plt.figure(figsize=(6, 6))
imgs_arr = [img, img_sobel_x, img_sobel_y, img_lap]
titles_arr = ['Original', 'x_gradient', 'y_gradient', 'laplacian']
for im, ti in zip(imgs_arr, titles_arr):
    spn += 1
    plt.subplot(spr, spc, spn)
    plt.axis('off')
    plt.title(ti)
    plt.imshow(im, cmap='gray')
plt.show()
